/**
 * 
 */
package truerefactor.codesmell;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import truerefactor.graph.ClassNode;
import truerefactor.graph.CodeGraph;
import truerefactor.refactor.Refactoring;

/**
 * @author Isaac
 *
 */
public class PrimitiveObsession extends CodeSmell {

    /**
     * 
     */
    public PrimitiveObsession()
    {
        this.shortName = "PRIOB";
        this.name = "Primitive Obsession";
        this.description = "";
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.codesmell.CodeSmell#measure(truerefactor.graph.CodeGraph, boolean, java.util.List)
     */
    @Override
    protected double measure(CodeGraph graph, boolean initial, List<List<Refactoring>> sequences)
    {
        List<ClassNode> classes = graph.getClasses();
        HashMap<ClassNode, Integer> novCounts = new HashMap<ClassNode, Integer>();
        
        int totalNOV = 0;
        for (ClassNode cNode : classes) {
            novCounts.put(cNode, cNode.getAttributes().size());
            totalNOV += cNode.getAttributes().size();
        }
        
        int avgV = totalNOV / classes.size();
        
        List<ClassNode> largeVClasses = new ArrayList<ClassNode>();
        for (ClassNode cNode : novCounts.keySet()) {
            if (novCounts.get(cNode) > avgV) {
                largeVClasses.add(cNode);
            }
        }
        
        Set<ClassNode> smellyClasses = new HashSet<ClassNode>();
        for (ClassNode cNode : largeVClasses) {
            smellyClasses.add(cNode);
            for (ClassNode parent : cNode.getParentClasses()) {
                smellyClasses.add(parent);
            }
            
            for (ClassNode subclass : cNode.getSubClasses()) {
                smellyClasses.add(subclass);
            }
        }
        
        Set<ClassNode> nonSmellyClasses = new HashSet<ClassNode>();
        for (ClassNode cNode : smellyClasses) {
            for (ClassNode assoc : cNode.getAssociatedClasses()) {
                nonSmellyClasses.add(assoc);
            }
        }
        
        smellyClasses.removeAll(nonSmellyClasses);
        
        return smellyClasses.size();
    }
}
